#ifndef Skeleton_h
#define Skeleton_h

#include "Memory/Pool.h"

class CModelJoint;
class CModelSkeleton;

namespace Skeleton {

class CPoseData
{
public:
	CPoseData();
	~CPoseData();

public:
	void SetMemoryPool(Memory::CPool* pMemoryPool) { m_pMemoryPool = pMemoryPool; }

	bool Initialize(const CModelSkeleton& skeleton);
	bool Initialize(const CPoseData& poseData);

	bool AllocateData(uint32 jointCount);
	void AllocationRelease();
	uint32 GetAllocationLength() const;

	ILINE uint32 GetJointCount() const { return m_jointCount; }
	ILINE QuatT* GetJointsRelative() { return SPU_LOCAL_PTR(m_pJointsRelative); }
	ILINE const QuatT* GetJointsRelative() const { return SPU_LOCAL_PTR(m_pJointsRelative); }
	ILINE QuatT* GetJointsAbsolute() { return SPU_LOCAL_PTR(m_pJointsAbsolute); }
	ILINE const QuatT* GetJointsAbsolute() const { return SPU_LOCAL_PTR(m_pJointsAbsolute); }
	ILINE Status4* GetJointsStatus() { return SPU_LOCAL_PTR(m_pJointsStatus); }
	ILINE const Status4* GetJointsStatus() const { return SPU_LOCAL_PTR(m_pJointsStatus); }

	void ComputeAbsolutePose(const CModelJoint* pJoints, bool singleRoot = false);
	void ComputeRelativePose(const CModelJoint* pJoints, bool singleRoot = false);

	ILINE void GetMemoryUsage(ICrySizer *pSizer) const;

#ifndef _RELEASE	
	bool ValidateRelPose(const CModelJoint* pJoints) const;
	bool ValidateAbsPose(const CModelJoint* pJoints) const;
#endif

public://private:
	uint32 m_jointCount;
	QuatT* m_pJointsRelative;
	QuatT* m_pJointsAbsolute;
	Status4* m_pJointsStatus;

	Memory::CPool* m_pMemoryPool;
};

ILINE void CPoseData::GetMemoryUsage(ICrySizer *pSizer) const
{
	pSizer->AddObject(m_pJointsRelative, m_jointCount * sizeof(QuatT));
	pSizer->AddObject(m_pJointsAbsolute, m_jointCount * sizeof(QuatT));
	pSizer->AddObject(m_pJointsStatus, m_jointCount * sizeof(Status4));
}

}; // namespace Skeleton

namespace LocatorHelper {

ILINE f32 ExtractMoveSpeed(const QuatT& rel)
{
	return rel.t.GetLength();
}

ILINE f32 ExtractTurnSpeed(const QuatT& rel)
{
	Vec3 v=rel.q.GetColumn1();
	return atan2_tpl(-v.x,v.y);
}

ILINE f32 ExtractTravelDir(const QuatT& rel)
{
	f32 tdir = atan2_tpl(-rel.t.x,rel.t.y);
	if (rel.t.y<0)
	{
		if (rel.t.x<0)
			tdir=+gf_PI-tdir;
		else
			tdir=-gf_PI-tdir;
	}
	return tdir;
}

ILINE f32 ExtractSlope(const QuatT& rel)
{
	f32 tdir = atan2_tpl(-rel.t.x,rel.t.y);
	Vec3 v=rel.t*Matrix33::CreateRotationZ(tdir);
	return atan2_tpl(v.z,v.y);
}

}

#endif // Skeleton_h
